/*
 * @Author: your name
 * @Date: 2021-06-04 07:16:21
 * @LastEditTime: 2022-03-17 18:55:56
 * @LastEditors: Please set LastEditors
 * @Description: 二级页属性，用于控制设置界面选定设置项后的二级页面内容
 * second_page是二级页属性，second_view是对second_page进行管理。
 */
#ifndef SECOND_PAGE_H
#define SECOND_PAGE_H
#include "gui_engine.h"
#include "xlog.h"
#include "page_handle.h"
#include <functional>
#include <map>
/**
 * @brief
 * 通用的宏定义
 */
#define VALUE_STRING_NAME "valueString"
#define ITEM_LABEL_NAME "itemName"
#define ITEM_FOCUS "itemFocus"
#define ITEM_SET "itemSet"
#define ITEM "item"
#define ITEM_STYLE "itemStyle"
#define CLOSE_468 "close468"
typedef struct
{
    std::function<void(void *)> callback;
} SettingCallback;
enum class HandleCmd
{
    // HANDLE_CMD_BT_PAIR_SUCCESSED = 0,
    // HANDLE_CMD_FORMAT_SUCCESSED,
    // HANDLE_CMD_FORMAT_FAILED,
    HANDLE_CMD_END
};
class SecondPageMsg
{
public:
    SecondPageMsg()
    {
        command = HandleCmd::HANDLE_CMD_END;
    }
    ~SecondPageMsg() = default;
    void SetCmd(HandleCmd cmd)
    {
        command = cmd;
    }
    void SetData(void *p)
    {
        ctx = p;
    }
    HandleCmd GetCmd()
    {
        return command;
    }
    void *GetData()
    {
        return ctx;
    }

private:
    HandleCmd command; //命令字
    void *ctx;         //数据，只传递指针，不管理指针
};
class SecondPage
{
public:
    SecondPage();
    virtual ~SecondPage();
    void SetContrlView(Widget *value);
    Widget *GetContrlView();
    /**
     * @brief
     * 按键事件触发二级页功能
     * @param ctx
     */
    virtual void ContrlSecondPage(void *ctx);
    void DefaultContrl(void *ctx);
    /**
     * @brief
     * 外界事件触发二级页功能，由具体的二级页设置handleEvent实现具体功能
     * @param msg 包含事件命令字与数据
     */
    void HandleMsg(SecondPageMsg msg) {}
    /**
     * @brief
     * 抽象的二级页打开渲染函数
     */
    virtual void StartDisplay() {}
    /**
     * @brief
     * 抽象的刷新函数
     */
    virtual void RefreshPage() {}
    /**
     * @brief
     * 抽象的带参数的二级页刷新函数，二级页有更复杂的操作时使用
     * 例如视频设置界面二级页对视频列表进行选择
     * @param ctx
     */
    virtual void RefreshPageV2(void *ctx) {}
    /**
     * @brief
     * 抽象的设置项被选中处理函数，派生类选择性重载实现具体功能。
     */
    virtual void ItemSelected() {}
    /**
     * @brief
     * 抽象的设置项重置按键功能映射表，在设置界面的设置项时固定调用。
     */
    virtual void ResetKeyCmd(KeyCmdMapTable &keyEvent);
    /**
     * @brief
     * 抽象的保存配置信息函数，由设置项触发当前页的抽象流程。
     */
    virtual void SaveConfiguration() {}
    /**
     * @brief
     * 发起刷新页面内容事件，刷新数据流程（流程有点绕弯，是为了保证对指针的有效引用）：
     * 第一，需要刷新页面数据时，由二级设置页调用RefreshPageEvent；
     * 第二,具体的设置页调用二级页重写后的RefreshPage函数；
     * 第三，重写的RefreshPage函数调用通用的渲染函数RefreshPageCommon完成刷新；
     */
    void RefreshPageEvent();
    /**
     * @brief
     * 通用的刷新操作
     */
    void RefreshPageCommon(std::string str);
    void ShowSaveTips(bool ret);
    void SetViewNum(unsigned int num)
    {
        viewNum = num;
    }
    unsigned int GetViewNum()
    {
        return viewNum;
    }
    void SetFuncNum(unsigned int num)
    {
        funcNum = num;
    }
    unsigned int GetFuncNum()
    {
        return funcNum;
    }
    template <typename T>
    void RefreshSlider(Widget *window, T funcSelected)
    {
        // Widget *window = GetThisPage();
        std::unique_ptr<Widget> view(GuiEngine::GetInstance().NewWidget());
        if (GuiEngine::GetInstance().Lookup(window, "slider", true, view.get()))
        {
            /**
             * @brief
             * 如果显示的所有item里面找到选择的下一个item，直接修改item属性进行选定
             */
            int tmp = static_cast<int>(T::FUNCTION_END);
            if (tmp - 1 == 0)
            {
                return;
            }
            int value = (100 / (tmp - 1)) * static_cast<int>(funcSelected);
            LOG_E("slider value=%d\n", 100 - value);
            GuiEngine::GetInstance().SliderSetValue(view.get(), 100 - value);
        }
    }

public:
    SettingCallback setEvent[static_cast<int>(KeyboardValue::KEYBOARD_VALUE_END) + 1];
    std::map<HandleCmd, std::function<void(void *)>> handleEvent;

private:
    /**
     * @brief
     * 由主界面分配给二级页的可支配空间
     * 只传递指针，不负责管理
     * 例如：xx功能渲染时，把可支配控件的“禁用”图标取消或者显示
     * 例如：刷新数据时，可支配空间的数据刷新
     */
    // Widget *view;
    std::unique_ptr<Widget> view;
    /**
     * @brief
     * 标志当前可控制的区域，主设置界面一共5个动态显示区域
     * 不同的区域有不同的动态操作方法
     */
    unsigned int viewNum;
    /**
     * @brief
     * 标志当前功能序号，主设置界面需要根据此参数确定如何去设置控件属性
     */
    unsigned int funcNum;
};
#endif